/*
 * Echqueserver.java
 *
 * Created on April 27, 2007, 8:17 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 *
 * @author Basel
 */
package eCheque;

import java.net.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.io.*;

public class Echqueserver implements Runnable {

	private final String SLASH = System.getProperty("file.separator");
	
	private Socket ServerConnection;
	private ObjectInputStream socketInputObject;
	private ObjectOutputStream socketOutputObject;
	private InputStream socketInput;
	private OutputStream socketOutput;

	public Echqueserver(Socket socket) {
		ServerConnection = socket;
	}

	private void getsocketStream() throws Exception {
		socketOutput = ServerConnection.getOutputStream();
		socketOutput.flush();
		socketInput = ServerConnection.getInputStream();

		socketOutputObject = new ObjectOutputStream(
				ServerConnection.getOutputStream());
		socketOutputObject.flush();
		socketInputObject = new ObjectInputStream(
				ServerConnection.getInputStream());
	}

	private void processConnection() throws IOException, ClassNotFoundException {
		EChequeResponse response = null;
		int code = socketInputObject.readInt();
		if (code == 0) {
			response = registerClientInfo();
		} else if (code == 1) {
			response = depositCheque();
		} else if (code == 2) {
			response = cancelCheque();
		} else if (code == 3) {
			response = getBalance();
		} else if (code == 4) {
			response = deleteAccount();
		}
		socketOutputObject.writeObject(response);
		socketOutputObject.flush();
	}
	
	private EChequeResponse deleteAccount() {
		EChequeResponse response = null;
		try {
			String accountNumber = socketInputObject.readObject().toString();
			EChequeDB db = new EChequeDB();
			String balanceSql = "DELETE FROM accounts WHERE accountID = ?;";
			PreparedStatement preparedStatement = null;
			try {
				preparedStatement = db.createPreparedStatement(balanceSql);
				preparedStatement.setString(1, accountNumber);
				db.executeUpdate(preparedStatement);
				response = new EChequeResponse(ResponseCode.OK);
			} catch (Exception e) {
				// primative logging
				e.printStackTrace();
				throw e;
			} finally {
				// No need to close the resultSet, it is closed
				// when the prepared statement is closed
				db.closePreparedStatement(preparedStatement);
			}
		} catch (Exception e) {
			response = new EChequeResponse(e);
		}
		return response;
	}

	private EChequeResponse getBalance() {
		EChequeResponse response = null;
		try {
			String accountNumber = socketInputObject.readObject().toString();
			EChequeDB db = new EChequeDB();
			String balanceSql = "SELECT balance FROM accounts WHERE accountID = ?;";
			ResultSet resultSet = null;
			PreparedStatement preparedStatement = null;
			try {
				preparedStatement = db.createPreparedStatement(balanceSql);
				preparedStatement.setString(1, accountNumber);
				resultSet = db.executeQuery(preparedStatement);
				if (resultSet.next()) {
					double balance = resultSet.getDouble(1);
					response = new EChequeResponse(ResponseCode.OK,
							Double.toString(balance));
				} else {
					response = new EChequeResponse(ResponseCode.ERROR,
							"Could not find account: " + accountNumber);
				}
			} catch (Exception e) {
				// primative logging
				e.printStackTrace();
				throw e;
			} finally {
				// No need to close the resultSet, it is closed
				// when the prepared statement is closed
				db.closePreparedStatement(preparedStatement);
			}
		} catch (Exception e) {
			response = new EChequeResponse(e);
		}
		return response;
	}

	private EChequeResponse registerClientInfo() throws IOException {
		EChequeResponse response = null;
		try {
			EChequeRegisteration registerClient = (EChequeRegisteration) socketInputObject
					.readObject();
			DigitalCertificate registDC = (DigitalCertificate) socketInputObject
					.readObject();

			String accountID = "'" + registerClient.getAccountNumber() + "',";
			String cerit = "'" + registerClient.getClientName() + "DC.edc"
					+ "',";
			String clientName = "'" + registerClient.getClientName() + "',";

			String registerStat = "insert into accounts(accountID,clientName,dcPath,balance) values("
					+ accountID + clientName + cerit + 100000 + ")";
			EChequeDB chqDB = new EChequeDB();
			if (chqDB.runDB(1, registerStat)) {
				DigitalCertificateIO dcIO = new DigitalCertificateIO();
				try {
					dcIO.SaveDC(registDC,
							"Bank" + SLASH + registerClient.getClientName()
									+ "DC.edc");
				} catch (IOException e) {
					// Unable to save the digital certificate. However,
					// the account was still created so continue on
					// primitive logging
					e.printStackTrace();
				}
				response = new EChequeResponse(ResponseCode.OK);
			} else {
				response = new EChequeResponse(ResponseCode.ERROR,
						"Failed to create account");
			}
		} catch (Exception e) {
			// primitive logging
			e.printStackTrace();
			response = new EChequeResponse(e);
		}

		return response;
	}

	private EChequeResponse depositCheque() {
		try {
			String depositResult = null;
			ECheque recivedCehq = (ECheque) socketInputObject.readObject();
			String depositAccount = (String) socketInputObject.readObject();

			String withdrawStat = "Select balance from accounts where accountID ="
					+ recivedCehq.getaccountNumber();
			double[] balanceValue = new double[1];

			EChequeDB chqDB = new EChequeDB();
			if (chqDB.runDB(0, withdrawStat, balanceValue)) {
				// check if the balance sufficient
				double chequeMoney = Double.parseDouble(recivedCehq.getMoney());
				if (chequeMoney <= balanceValue[0]) {
					// cheque that the cheque is not canceld
					withdrawStat = "Select * from cancelledCheque where accountID ='"
							+ recivedCehq.getaccountNumber()
							+ "'and chequeID ='"
							+ recivedCehq.getchequeNumber() + "'";
					if (!chqDB.runDB(withdrawStat, 0)) {
						withdrawStat = "Select * from eChequeOut where chequeID='"
								+ recivedCehq.getchequeNumber()
								+ "'and accountID='"
								+ recivedCehq.getaccountNumber() + "'";
						if (!chqDB.runDB(withdrawStat, 0)) {
							withdrawStat = "Update accounts set balance = balance -"
									+ chequeMoney
									+ "where accountID ="
									+ recivedCehq.getaccountNumber();
							chqDB.runDB(1, withdrawStat);
							withdrawStat = "Update accounts set balance = balance +"
									+ chequeMoney
									+ "where accountID ="
									+ depositAccount;
							chqDB.runDB(1, withdrawStat);

							// update cheque out and in table
							String cheqUpdate = "Insert into eChequeOut(chequeID, accountID, balance) values("
									+ "'"
									+ recivedCehq.getchequeNumber()
									+ "','"
									+ recivedCehq.getaccountNumber()
									+ "'," + chequeMoney + ")";
							chqDB.runDB(1, cheqUpdate);

							cheqUpdate = "Insert into eChequeIN(chequeID, accountID, balance) values("
									+ "'"
									+ recivedCehq.getchequeNumber()
									+ "','"
									+ recivedCehq.getaccountNumber()
									+ "'," + chequeMoney + ")";
							chqDB.runDB(1, cheqUpdate);

							// report the deposit result
							return new EChequeResponse(ResponseCode.OK,
									"Your account has received the deposited cheque\nYour balance has been incremented by"
											+ recivedCehq.getMoney());
						} else {
							// report the deposit result
							depositResult = "This cheque has already been deposited\nSorry, it cannot be deposited twice";

						}
					} else {
						// report the deposit result
						depositResult = "This cheque has been canceled by the drawer\nSorry, it cannot be deposited";
					}
				} else {
					// report the deposit result
					depositResult = "Drawer balance is not sufficient for withdrawing\n";
				}
			} else {
				depositResult = "This cheque does not belong to one of our customers\nYou have to connect to the drawer bank server";
			}

			return new EChequeResponse(ResponseCode.ERROR, depositResult);
		} catch (Exception e) {
			return new EChequeResponse(e);
		}
	}

	private EChequeResponse cancelCheque() {
		EChequeResponse response = null;
		try {
			ECheque recivedCehq = (ECheque) socketInputObject.readObject();
			String cancelChequeStat = "insert into cancelledCheque (accountID,chequeID) values('"
					+ recivedCehq.getaccountNumber()
					+ "','"
					+ recivedCehq.getchequeNumber() + "')";

			EChequeDB chqDB = new EChequeDB();
			if (chqDB.runDB(1, cancelChequeStat)) {
				response = new EChequeResponse(ResponseCode.OK);
			} else {
				response = new EChequeResponse(ResponseCode.ERROR,
						"Failed to cancel cheque");
			}
		} catch (Exception e) {
			response = new EChequeResponse(e);
		}

		return response;
	}

	private void closeConnection() {
		try {
			socketInput.close();
			socketOutput.close();
			socketInputObject.close();
			socketOutputObject.close();
			ServerConnection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void RunServer() {
		try {
			getsocketStream();
			processConnection();
		} catch (Exception error) {
			error.printStackTrace();
		} finally {
			closeConnection();
		}
	}

	public void run() {
		RunServer();
	}

}